#pragma once

/*************************	Header *****************************/

#include "hamiltonian.h"

using arma::mat;
using arma::cx_mat;

/*********************** Declaration ***************************/

// The Density of States (DoS) Functor.
//
//	This function object is used to calculate the DoS for a given 
//	 unit. The DoS is calculated from a k-point sampling of the 
//	Green's function i.e density of states with broadening.
//	This functor include to date the calculation of the following:
//
//	-	The DoS(hw) for a given Unit.
//
// Options:
//	The options are public variables (accessable from outside the
//	class) and are set to default value at class construction time.
//
// (System*) system;		Default:	&System::Std
//		A pointer to the used system. The system contains variables 
//		needed to construct elements (coupling strengths etc.).
//		The system defaults to a statically generated system (the
//		standard system).
//
// (double) bias;			Default:	0
//		A double containing the current bias (for bi-layered 
//		systems).
//		The bias defaults to 0 i.e no bias.
//
// (vec) E;			Default:	vec(0)
//		A  double vector containing the energy sample points used in
//		the calculations. The size of this has little influence on 
//		the operation time.
//		The E defaults to vec(0) i.e only one sample point.
//
// (double) eta;			Default:	0.001
//		A double containing the broadening factor.
//		The eta defaults to 0.001.
//
// (size_t) N_samples;	Default:	1000
//		An integer containing the number of k-points to use in the
//		calculations of the Green's function matrix.
//		The N_samples defaults to 1000.
//
// (func) updateProgress;	Default:	null
//		A function object containing an updating function to report
//		 the progress of calculations.
//		The updateProgress defaults to null i.e no function.
//
// Usage:
//	This function includes the following public operating functions.
//
//	(DensityOfStates &) operator()(int id)
//		This operator (use by simply appending () to a DensityOfStates
//		type variable) calculates the density of states for the unit
//		id. The operator returns the object it self for easy access
//		to result. The result is stored in the DoS result variable. The 
//		variable may be retrieved immidiately after calculation i.e:
//		dos(id).DoS // Calculate and retreive result.
// 
// Example:
//	Set options and get DoS:
//
//		DensityOfStates dos; // Generate a hamilton object
//
//		dos.bias = current_bias; // Set the current bias
//		dos.E = current_energies; // Set the current energies
//
//		return dos(id).DoS; // Calculate and return result.
class GRAPHENETOOLS_DLL_API DensityOfStates
{
// Options:
public:
	// A pointer to the used system. The system contains variables 
	// needed to construct elements (coupling strengths etc.).
	System* system;
	// A double containing the current bias (for bi-layered 
	// systems).
	double bias;
	// A  double vector containing the energy sample points used in
	// the calculations. The size of this has little influence on 
	// the operation time.
	vec E;
	// A double containing the broadening factor.
	double eta;
	// An integer containing the number of k-points to use in the
	// calculations of the Green's function matrix.
	size_t N_samples;
	// A function object containing an updating function to report
	// the progress of calculations.
	std::function< void (const double &)> updateProgress;

// Usage:
	// This operator (use by simply appending () to a DensityOfStates
	// type variable) calculates the density of states for the unit
	// id. The operator returns the object it self for easy access
	// to result. The result is stored in the DoS result variable. The 
	// variable may be retrieved immidiately after calculation i.e:
	// dos(id).DoS // Calculate and retreive result.
	DensityOfStates & operator()(int id);

// Results:

	// The density of states for a Unit. Use 
	// operator()(int id) to set.
	vec DoS;
	
// Constructor
	DensityOfStates(void);
	
protected:
	// This variable contains the update step
	double step;
	// This function attempts to update the progress.
	void try_updateProgress() const;

	// This function returns the Hamilton matrix H.
	cx_mat getHamiltonMatrix(int id, const vec &k) const;
	// This function returns a randomly generated uniform distribution of k-points.
	mat getPseudoUniformKDistribution(int id, int &weight) const;
	// A random point generator (in triangle)!
	static vec randomPoint(const vec &p_1, const vec &p_2, const vec &p_3);
};

